use std::cmp::{Ordering, min};
use fixed::types::I28F4;

#[derive(Debug, PartialEq)]
pub enum Side { BOTH, DR, CR, ZERO }

#[derive(Clone, Debug)]
pub struct Accrual {
    pub dr: I28F4,
    pub cr: I28F4,
    pub swapped: bool
}

impl Accrual {

    pub fn side(&self) -> Side {
        if self.cr != 0 && self.dr != 0 {
            Side::BOTH
        } else if self.cr == 0 && self.dr == 0 {
            Side::ZERO
        } else {
            match self.dr.cmp(&self.cr) {
                Ordering::Less =>    Side::CR,
                Ordering::Greater => Side::DR,
                Ordering::Equal =>   Side::BOTH
            }
        }
    }

    pub fn counter_side(&self) -> Side {
        match self.side() {
            Side::CR => Side::DR,
            Side::DR => Side::CR,
            Side::BOTH => Side::ZERO,
            Side::ZERO => Side::BOTH
        }
    }

    pub fn counter(&self) -> Accrual {
        Accrual {cr: self.dr, dr:self.cr, swapped: false}
    }

    pub fn swap(&mut self) -> &Accrual {
        let &mut Accrual {dr, cr, swapped} = self;
        self.dr = cr;
        self.cr = dr;
        self.swapped = !swapped;
        self
    }

    pub fn plus(&mut self, other: &Accrual) -> &Accrual {

        if self.swapped != other.swapped {
            panic!("Incompatible swapping condition");
        }

        self.cr += other.cr;
        self.dr += other.dr;
        self
    }

    pub fn duct(&mut self, other: &Accrual) -> Accrual {
        let &mut Accrual {dr: orig_dr, cr: orig_cr, ..} = self;
        let &Accrual {dr: curr_dr, cr: curr_cr, swapped: curr_swapped} = other;

        let dr = min(orig_dr, curr_dr);
        let cr = min(orig_cr, curr_cr);

        println!("{} {}", dr, cr);

        self.dr -= dr;
        self.cr -= cr;

        return Accrual {dr: cr, cr: dr, swapped: curr_swapped};
    }
}

#[macro_export]
macro_rules! accro {

    ( $dr:expr, $cr:expr ) => {
        Accrual {
            dr: fixed!($dr: I28F4),
            cr: fixed!($cr: I28F4),
            swapped: false
        }
    };
}
